package com.niiwoo.civet.account.service.local.withdraw;/**
 * Created by DELL on 2017/12/5.
 */

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.niiwoo.activity.stage.dto.request.prize.ActivityPrizeResetStatusReqDTO;
import com.niiwoo.activity.stage.dto.response.prize.UserPrizeResponseDTO;
import com.niiwoo.activity.stage.enums.prize.UserPrizeUseEnum;
import com.niiwoo.activity.stage.service.prize.ActivityPrizeDubboService;
import com.niiwoo.civet.account.dao.entity.*;
import com.niiwoo.civet.account.dao.mapper.RollbackRechargeOrderMapper;
import com.niiwoo.civet.account.dao.mapper.WithdrawOrderMapper;
import com.niiwoo.civet.account.dao.mapper.WithdrawOrderMapperExt;
import com.niiwoo.civet.account.dto.SubmitLoanWithdrawRequestDTO;
import com.niiwoo.civet.account.dto.WithdrawFeeDTO;
import com.niiwoo.civet.account.dto.bill.AddBillAndChangeBalanceDTO;
import com.niiwoo.civet.account.dto.bill.AddBillDetailDTO;
import com.niiwoo.civet.account.dto.common.MoneyTotalDTO;
import com.niiwoo.civet.account.dto.common.sendmessage.SendMsgForWithdrawDTO;
import com.niiwoo.civet.account.dto.request.WithdrawNotifyRequestDTO;
import com.niiwoo.civet.account.dto.response.WithdrawT0CheckResponse;
import com.niiwoo.civet.account.enums.*;
import com.niiwoo.civet.account.service.local.AccountService;
import com.niiwoo.civet.account.service.local.BankCardService;
import com.niiwoo.civet.account.service.local.MessageSendLocalService;
import com.niiwoo.civet.account.service.local.MoneyTotalLocalService;
import com.niiwoo.civet.account.service.local.bill.BillFacade;
import com.niiwoo.civet.account.service.local.lend.ProjectLendAccountingLocalService;
import com.niiwoo.civet.base.enums.ChannelCodeEnum;
import com.niiwoo.civet.trade.constant.PlatformConstant;
import com.niiwoo.civet.trade.enums.TradeConfigEnum;
import com.niiwoo.civet.trade.service.configure.TradeConfigDubboService;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.lanmao.component.LanMaoDirectService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.LanMaoErrorCodeEnum;
import com.niiwoo.tripod.lanmao.enums.RemitTypeEnum;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.lanmao.enums.WithdrawTypeEnum;
import com.niiwoo.tripod.lanmao.request.AutoWithdrawRequest;
import com.niiwoo.tripod.lanmao.request.ConfirmWithdrawRequest;
import com.niiwoo.tripod.lanmao.request.QueryUserInformationRequest;
import com.niiwoo.tripod.lanmao.response.AutoWithdrawResponse;
import com.niiwoo.tripod.lanmao.response.ConfirmWithdrawResponse;
import com.niiwoo.tripod.lanmao.response.QueryUserInformationResponse;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * 提现处理Facade
 *
 * @author xiaoyingping
 * @create 2017-12-05 16:09
 **/
@Service
@Slf4j
public class WithdrawService {

    @Autowired
    private WithdrawOrderService withdrawOrderService;
    @Autowired
    private WithdrawConfirmOrderService withdrawConfirmOrderService;
    @Autowired
    private WithdrawCancelOrderService withdrawCancelOrderService;
    @Autowired
    private WithdrawOrderAuditService withdrawOrderAuditService;
    @Autowired
    private BillFacade billFacade;
    @Autowired
    private LanMaoDirectService lanMaoDirectService;
    @Autowired
    private AccountService accountService;
    @Autowired
    private WithdrawOrderMapper withdrawOrderMapper;
    @Autowired
    private WithdrawOrderMapperExt withdrawOrderMapperExt;
    @Autowired
    private RollbackRechargeOrderMapper rollbackRechargeOrderMapper;
    @Autowired
    private MoneyTotalLocalService moneyTotalLocalService;
    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
    @Autowired
    private LanMaoSequence lanMaoSequence;
    @Autowired
    private BankCardService bankCardService;
    @Autowired
    private PrivacyMasks privacyMasks;
    @Autowired
    MessageSendLocalService messageSendLocalService;
    @Autowired
    ProjectLendAccountingLocalService projectLendAccountingLocalService;


    @Reference(version = "1.0.0")
    private TradeConfigDubboService tradeConfigDubboService;

    @Reference(version = "1.0.0")
    private ActivityPrizeDubboService activityPrizeDubboService;


    /**
     * 检查是否支持能T0提现
     *
     * @param accountBase
     * @param withdrawAmount
     * @return
     */
    public WithdrawT0CheckResponse checkT0Enable(AccountBase accountBase, BigDecimal withdrawAmount) {
        WithdrawT0CheckResponse withdrawT0CheckResponse = new WithdrawT0CheckResponse();

        //同一账户只能有一笔待确认T0
        withdrawT0CheckResponse.setHasFastWithdrawInApprove(Boolean.FALSE);
        List<WithdrawOrder> withdrawOrderList = withdrawOrderService.listT0WithdrawOrdersByAccountId(accountBase.getId());
        if(!withdrawOrderList.isEmpty()){
            log.info("同一账户只能有一笔待确认T0：{}", accountBase.getUserId());
            withdrawT0CheckResponse.setHasFastWithdrawInApprove(Boolean.TRUE);
            withdrawT0CheckResponse.setT0Enable(Boolean.FALSE);
            withdrawT0CheckResponse.setAdvanceAmount(BigDecimal.ZERO);
            return withdrawT0CheckResponse;
        }

        //实时查询存管上的平台垫资账户余额
        AccountBase platformUrgentAccount = accountService.loadNiiwooAccount(PlatformConstant.PLATFORM_USER_ID, UserRoleEnum.PLATFORM_URGENT);
        QueryUserInformationResponse advanceAccount = queryAccountInfoRealTime(platformUrgentAccount.getAccountNo());
        BigDecimal advanceBalanceAmount = advanceAccount.getBalance();

        //查询垫资阀值
        Map<String, String> tradeConfigMap = tradeConfigDubboService.selectTradeConfigByEmuns(Arrays.asList(TradeConfigEnum.WITHDRAWADVANCETHRESHOLD));
        log.info("提现时垫资账户最低留存的阀值:{}", tradeConfigMap.get(TradeConfigEnum.WITHDRAWADVANCETHRESHOLD.getConfigKey()));
        BigDecimal withdrawAdvanceThreshold = new BigDecimal(tradeConfigMap.get(TradeConfigEnum.WITHDRAWADVANCETHRESHOLD.getConfigKey()));

        //查询当前的应垫付总额
        BigDecimal advanceAmountTotal = withdrawOrderService.queryAdvanceAmountTotal();
        log.info("用户账户号:{}, 提现金额:{}, 垫资账户实时余额:{}, 垫资阀值:{}, 目前平台应垫付总额:{}", accountBase.getAccountNo(), withdrawAmount, advanceBalanceAmount, withdrawAdvanceThreshold, advanceAmountTotal);

        //判断是否能够T0提现:垫资账户实时余额 - 应垫资总额 - 本次需垫资金额  >= 阀值
        Boolean t0Enable = Boolean.FALSE;
        if (advanceBalanceAmount.subtract(advanceAmountTotal).subtract(withdrawAmount).compareTo(withdrawAdvanceThreshold) >= 0) {
            t0Enable = Boolean.TRUE;
        }

        //返回结果
        withdrawT0CheckResponse.setT0Enable(t0Enable);
        withdrawT0CheckResponse.setAdvanceAmount(withdrawAmount);
        return withdrawT0CheckResponse;
    }


    /**
     * 申请提现回调处理
     *
     * @param notifyRequest
     * @return
     */
    @Transactional
    public Long processSubmitWithdrawNotify(WithdrawNotifyRequestDTO notifyRequest) {
        //查询并锁定提现订单
        String requestNo = notifyRequest.getRequestNo();
        WithdrawOrder withdrawOrder = withdrawOrderService.loadWithdrawOrderByRequestNo(requestNo);
        withdrawOrder = withdrawOrderMapperExt.selectByPrimaryKeyForUpdate(withdrawOrder.getId());
        if (withdrawOrder.getStatus().equals(WithdrawOrderStatusEnum.PRE_SUBMISSION.getCode())) {
            log.info("提现订单目前是预提交状态：{}", JSON.toJSONString(withdrawOrder));
            //修改提现订单的状态和实际垫付金额
            WithdrawOrder withdrawOrderRecord = new WithdrawOrder();
            withdrawOrderRecord.setId(withdrawOrder.getId());
            withdrawOrderRecord.setStatus(WithdrawOrderStatusEnum.WAIT_CONFIRM.getCode());
            withdrawOrderRecord.setAuditStatus(WithdrawOrderAuditStatusEnum.AUDIT.getValue());
            withdrawOrderMapper.updateByPrimaryKeySelective(withdrawOrderRecord);
            //新增提现审核记录
            WithdrawOrderAudit withdrawOrderAudit = new WithdrawOrderAudit();
            withdrawOrderAudit.setWithdrawOrderId(withdrawOrder.getId());
            withdrawOrderAudit.setApplyTime(withdrawOrder.getCreateTime());
            withdrawOrderAuditService.addWithdrawOrderAudit(withdrawOrderAudit);
            //增加提现冻结总额
            MoneyTotalDTO moneyTotalDTO = new MoneyTotalDTO();
            moneyTotalDTO.setUserId(withdrawOrder.getUserId());
            moneyTotalDTO.setAccountId(withdrawOrder.getAccountId());
            moneyTotalDTO.setAmountType(AccountAmountTypeEnum.WITHDRAW_FREEZE);
            moneyTotalDTO.setAmount(withdrawOrder.getAmount());
            moneyTotalLocalService.moneyTotal(moneyTotalDTO);
            //新增用户账单和平台账单
            this.saveAccountBillList(withdrawOrder);
            //增加应垫资总额
            withdrawOrderService.increAdvanceAmountTotal(withdrawOrder.getAdvanceAmount());
        }else {
            log.info("提现订单目前是非预提交状态，因此不做任何处理：{}", JSON.toJSONString(withdrawOrder));
        }

        return withdrawOrder.getId();

    }

    /**
     * 确认提现
     *
     * @param withdrawOrderId
     */

    public void confirmWithdraw(Long withdrawOrderId) {
        //获取自身代理
        WithdrawService withdrawService = (WithdrawService) AopContext.currentProxy();
        //查询提现订单
        WithdrawOrder withdrawOrder = withdrawOrderService.getWithdrawOrderByIdFromMaster(withdrawOrderId);
        if (!WithdrawOrderStatusEnum.WAIT_CONFIRM.getCode().equals(withdrawOrder.getStatus())
                || !WithdrawOrderAuditStatusEnum.PASS.getValue().equals(withdrawOrder.getAuditStatus())) {
            log.error("提现确认,订单状态有误:{}", JSON.toJSONString(withdrawOrder));
            throw new BizException("ACC10036");
        }

        //用户提现申请时提交的应垫资金额
        BigDecimal oriAdvanceAmount = withdrawOrder.getAdvanceAmount();

        //自动提现
        if (WithdrawAutoType.AUTO.getValue().equals(withdrawOrder.getIsAuto())) {
            //查询账户
            AccountBase accountBase = accountService.loadAccountById(withdrawOrder.getAccountId());
            AutoWithdrawRequest autoWithdrawRequest = new AutoWithdrawRequest();
            autoWithdrawRequest.setRequestNo(withdrawOrder.getRequestNo());
            autoWithdrawRequest.setPlatformUserNo(accountBase.getAccountNo());
            autoWithdrawRequest.setWithdrawType(WithdrawTypeEnum.URGENT);
            autoWithdrawRequest.setAmount(withdrawOrder.getAmount());
            //懒猫提现接口佣金为0时不能传递，否则报错。
            if(withdrawOrder.getRealFee() != null && withdrawOrder.getRealFee().compareTo(BigDecimal.ZERO)>0){
                autoWithdrawRequest.setCommission(withdrawOrder.getRealFee());
            }
            CompletableFuture<AutoWithdrawResponse> future = lanMaoDirectService.autoWithdraw(autoWithdrawRequest);
            AutoWithdrawResponse autoWithdrawResponse = null;
            try {
                log.info("懒猫自动提现请求{}:{}",withdrawOrder.getRequestNo(),JSON.toJSONString(autoWithdrawRequest));
                autoWithdrawResponse = future.get();
                log.info("懒猫自动提现响应{}:{}",withdrawOrder.getRequestNo(),JSON.toJSONString(autoWithdrawResponse));
            } catch (Exception e) {
                log.error("懒猫自动提现接口调用异常{}:{}",withdrawOrder.getRequestNo(),JSON.toJSONString(autoWithdrawResponse), e);
                return;
            }
            if (autoWithdrawResponse.isSuccess()) {
                //更新提现订单状态为出款中
                withdrawService.withdrawConfirmSuccess(withdrawOrderId,null,autoWithdrawResponse.getFloatAmount(),autoWithdrawResponse.getRemitType());
            } else {
                log.info("懒猫自动提现失败{}:{}",withdrawOrder.getRequestNo(),JSON.toJSONString(autoWithdrawResponse));
                if (!LanMaoErrorCodeEnum.REQUEST_NO_REPEAT.getCode().equals(autoWithdrawResponse.getErrorCode())
                       && !LanMaoErrorCodeEnum.SYSTEM_ERROR.getCode().equals(autoWithdrawResponse.getErrorCode())) {
                    withdrawService.withdrawPaymentFail(withdrawOrder.getRequestNo(), 0L, WithdrawEndTypeEnum.SYSTEM_AUTO);
                }else{
                    log.error("懒猫自动提现提示流水号重复:{}",withdrawOrder.getRequestNo());
                }
            }
        }
        //待确认提现
        else {
            //初始化提现确认订单
            WithdrawConfirmOrder withdrawConfirmOrder = withdrawService.initWithdrawConfirm(withdrawOrderId);
            //向存管发送同意提现的命令
            ConfirmWithdrawRequest confirmWithdrawRequest = new ConfirmWithdrawRequest();
            confirmWithdrawRequest.setRequestNo(withdrawConfirmOrder.getRequestNo());
            confirmWithdrawRequest.setPreTransactionNo(withdrawOrder.getRequestNo());
            confirmWithdrawRequest.setWithdrawType(WithdrawTypeEnum.enumOf(withdrawOrder.getWithdrawType()));
            CompletableFuture<ConfirmWithdrawResponse> future = lanMaoDirectService.confirmWithdraw(confirmWithdrawRequest);
            ConfirmWithdrawResponse confirmWithdrawResponse = null;
            try {
                log.info("懒猫提现确认请求{}：{}",withdrawOrder.getRequestNo(),JSON.toJSONString(confirmWithdrawRequest));
                confirmWithdrawResponse = future.get();
                log.info("懒猫提现确认响应{}：{}",withdrawOrder.getRequestNo(),JSON.toJSONString(confirmWithdrawResponse));
            } catch (Exception e) {
                log.error("懒猫提现确认接口调用异常{}:{}",withdrawOrder.getRequestNo(),JSON.toJSONString(confirmWithdrawRequest), e);
                withdrawService.updateWithdrawConfirm(withdrawOrderId, withdrawConfirmOrder.getId(), WithdrawConfirmOrderStatusEnum.TIMEOUT);
            }
            if (confirmWithdrawResponse != null) {
                if (confirmWithdrawResponse.isSuccess()) {
                    //提现确认成功，更新提现确认订单，更新提现订单为出款中，刷新垫资金额
                    withdrawService.withdrawConfirmSuccess(withdrawOrderId,withdrawConfirmOrder.getId(),
                            confirmWithdrawResponse.getFloatAmount(),
                            confirmWithdrawResponse.getRemitType());
                } else {
                    log.error("懒猫提现确认失败{}：{}",withdrawOrder.getRequestNo(),JSON.toJSONString(confirmWithdrawResponse));
                    withdrawService.updateWithdrawConfirm(withdrawOrderId, withdrawConfirmOrder.getId(), WithdrawConfirmOrderStatusEnum.FAIL);
                }
            }
        }
        //减少应垫付总额
        withdrawOrderService.decreAdvanceAmountTotal(oriAdvanceAmount);
    }

    /**
     * 取消提现
     *
     * @param withdrawOrderId
     */
    public void cancelWithdraw(Long withdrawOrderId) {
        WithdrawEndTypeEnum endTypeEnum = WithdrawEndTypeEnum.SYSTEM_AUTO;

        //获取自身代理
        WithdrawService withdrawService = (WithdrawService) AopContext.currentProxy();
        //查询提现订单
        WithdrawOrder withdrawOrder = withdrawOrderService.getWithdrawOrderByIdFromMaster(withdrawOrderId);
        if (!WithdrawOrderStatusEnum.WAIT_CONFIRM.getCode().equals(withdrawOrder.getStatus())
                || !WithdrawOrderAuditStatusEnum.NOT_PASS.getValue().equals(withdrawOrder.getAuditStatus())) {
            log.error("提现确认,订单状态有误:{}", JSON.toJSONString(withdrawOrder));
            throw new BizException("ACC10036");
        }
        //自动提现
        if (WithdrawAutoType.AUTO.getValue().equals(withdrawOrder.getIsAuto())) {
            //直接走提现失败分支
            withdrawService.withdrawPaymentFail(withdrawOrder.getRequestNo(), 0L, WithdrawEndTypeEnum.SYSTEM_AUTO);
        }
        //待确认提现
        else {
            //初始化提现取消订单
            WithdrawCancelOrder withdrawCancelOrder = withdrawService.initWithdrawCancel(withdrawOrderId);
            //向存管发送取消提现的命令
            ConfirmWithdrawRequest confirmWithdrawRequest = new ConfirmWithdrawRequest();
            confirmWithdrawRequest.setRequestNo(withdrawCancelOrder.getRequestNo());
            confirmWithdrawRequest.setPreTransactionNo(withdrawOrder.getRequestNo());
            CompletableFuture<ConfirmWithdrawResponse> future = lanMaoDirectService.cancelWithdraw(confirmWithdrawRequest);
            ConfirmWithdrawResponse confirmWithdrawResponse = null;
            try {
                log.info("懒猫提取消请求{}：{}",withdrawOrder.getRequestNo(),JSON.toJSONString(confirmWithdrawRequest));
                confirmWithdrawResponse = future.get();
                log.info("懒猫提现取消响应{}：{}",withdrawOrder.getRequestNo(),JSON.toJSONString(confirmWithdrawResponse));
            } catch (Exception e) {
                log.error("懒猫提现取消接口调用异常:{}", JSON.toJSONString(confirmWithdrawRequest), e);
                withdrawService.updateWithdrawCancel(withdrawOrderId, withdrawCancelOrder.getId(), WithdrawCancelOrderStatusEnum.TIMEOUT, withdrawOrder.getRequestNo(), endTypeEnum);
            }
            if (confirmWithdrawResponse != null) {
                if (confirmWithdrawResponse.isSuccess()) {
                    withdrawService.updateWithdrawCancel(withdrawOrderId, withdrawCancelOrder.getId(), WithdrawCancelOrderStatusEnum.SUCCESS, withdrawOrder.getRequestNo(), endTypeEnum);
                } else {
                    withdrawService.updateWithdrawCancel(withdrawOrderId, withdrawCancelOrder.getId(), WithdrawCancelOrderStatusEnum.FAIL, withdrawOrder.getRequestNo(), endTypeEnum);
                }
            }
        }
        //减少应垫付总额
        withdrawOrderService.decreAdvanceAmountTotal(withdrawOrder.getAdvanceAmount());
    }


    /**
     * 提现出款成功
     *
     * @param requestNo
     * @param updateUserId
     */
    @Transactional
    public void withdrawPaymentSuccess(String requestNo, Long updateUserId, WithdrawEndTypeEnum endTypeEnum) {
        //查询并锁定提现订单表
        WithdrawOrder withdrawOrder = withdrawOrderService.loadWithdrawOrderByRequestNo(requestNo);
        Long withdrawOrderId = withdrawOrder.getId();
        withdrawOrder = withdrawOrderMapperExt.selectByPrimaryKeyForUpdate(withdrawOrderId);
        //判断提现状态是否是在“出款中”
        if (withdrawOrder.getStatus().equals(WithdrawOrderStatusEnum.OUTING.getCode())) {
            //修改提现订单状态
            withdrawOrderService.successWithdrawOrder(withdrawOrderId, updateUserId, endTypeEnum);
            //修改账单状态为成功
            billFacade.successBillByOrderId(withdrawOrder.getUserId(), withdrawOrderId.toString(), OrderTypeEnum.WITHDRAW);
            //增加累计提现总额
            MoneyTotalDTO withdrawMoneyTotalDTO = new MoneyTotalDTO();
            withdrawMoneyTotalDTO.setUserId(withdrawOrder.getUserId());
            withdrawMoneyTotalDTO.setAccountId(withdrawOrder.getAccountId());
            withdrawMoneyTotalDTO.setAmountType(AccountAmountTypeEnum.WITHDRAW_TOTAL);
            withdrawMoneyTotalDTO.setAmount(withdrawOrder.getRealAmout());
            moneyTotalLocalService.moneyTotal(withdrawMoneyTotalDTO);
            //增加累计提现手续费
            if (withdrawOrder.getRealFee().compareTo(BigDecimal.ZERO) > 0) {
                MoneyTotalDTO withdrawFeeMoneyTotalDTO = new MoneyTotalDTO();
                withdrawFeeMoneyTotalDTO.setUserId(withdrawOrder.getUserId());
                withdrawFeeMoneyTotalDTO.setAccountId(withdrawOrder.getAccountId());
                withdrawFeeMoneyTotalDTO.setAmountType(AccountAmountTypeEnum.WITHDRAW_FEE);
                withdrawFeeMoneyTotalDTO.setAmount(withdrawOrder.getRealFee());
                moneyTotalLocalService.moneyTotal(withdrawFeeMoneyTotalDTO);
            }
            //减少提现冻结总额(平台提现为直连提现，无冻结金额)
            if(!PlatformConstant.PLATFORM_USER_ID.equals(withdrawOrder.getUserId())){
                MoneyTotalDTO withdrawFreezeMoneyTotalDTO = new MoneyTotalDTO();
                withdrawFreezeMoneyTotalDTO.setAccountId(withdrawOrder.getAccountId());
                withdrawFreezeMoneyTotalDTO.setUserId(withdrawOrder.getUserId());
                withdrawFreezeMoneyTotalDTO.setAmountType(AccountAmountTypeEnum.WITHDRAW_FREEZE);
                withdrawFreezeMoneyTotalDTO.setAmount(BigDecimal.ZERO.subtract(withdrawOrder.getAmount()));
                moneyTotalLocalService.moneyTotal(withdrawFreezeMoneyTotalDTO);
            }


            //如果是融360的标的需要通知
            if (WithdrawBusinessTypeEnum.R360_USER_LOAN.getValue().equals(withdrawOrder.getBusinessType())
                    || WithdrawBusinessTypeEnum.CARD_NIU_USER_LOAN.getValue().equals(withdrawOrder.getBusinessType())
                    || WithdrawBusinessTypeEnum.ORG_USER_LOAN.getValue().equals(withdrawOrder.getBusinessType())){
                projectLendAccountingLocalService.autoWithdrawResultNotify(withdrawOrder.getId(), WithdrawOrderStatusEnum.SUCCESS.getCode());
            }
        }
    }

    /**
     * 提现出款失败
     *
     * @param requestNo
     * @param updateUserId
     */
    @Transactional
    public void withdrawPaymentFail(String requestNo, Long updateUserId, WithdrawEndTypeEnum endTypeEnum) {
        //查询并锁定提现订单表
        WithdrawOrder tempWithdrawOrder = withdrawOrderService.loadWithdrawOrderByRequestNo(requestNo);
        Long withdrawOrderId = tempWithdrawOrder.getId();
        WithdrawOrder withdrawOrder = withdrawOrderMapperExt.selectByPrimaryKeyForUpdate(withdrawOrderId);
        //判断如果已经是失败，直接返回
        if (WithdrawOrderStatusEnum.FAIL.getCode().equals(withdrawOrder.getStatus())) {
            log.info("提现订单的当前状态为已失败，不需要再处理");
            return;
        }

        if(PlatformConstant.PLATFORM_USER_ID.equals(withdrawOrder.getUserId())){
            withdrawPaymentPlateFail(withdrawOrder,updateUserId,endTypeEnum);
        }else {
            //修改提现确认订单状态
            withdrawOrderService.failWithdrawOrder(withdrawOrderId, updateUserId, endTypeEnum);
            //关闭账单
            billFacade.closeAndRevertBill(withdrawOrderId.toString(), OrderTypeEnum.WITHDRAW,"");

            if (withdrawOrder.getStatus().equals(WithdrawOrderStatusEnum.SUCCESS.getCode())) {
                //以前是提现成功过，则需要减少累计提现总额和提现手续费
                MoneyTotalDTO withdrawTotalDTO = new MoneyTotalDTO();
                withdrawTotalDTO.setUserId(withdrawOrder.getUserId());
                withdrawTotalDTO.setAccountId(withdrawOrder.getAccountId());
                withdrawTotalDTO.setAmountType(AccountAmountTypeEnum.WITHDRAW_TOTAL);
                withdrawTotalDTO.setAmount(BigDecimal.ZERO.subtract(withdrawOrder.getRealAmout()));
                moneyTotalLocalService.moneyTotal(withdrawTotalDTO);

                MoneyTotalDTO withdrawFeeTotalDTO = new MoneyTotalDTO();
                withdrawFeeTotalDTO.setUserId(withdrawOrder.getUserId());
                withdrawFeeTotalDTO.setAccountId(withdrawOrder.getAccountId());
                withdrawFeeTotalDTO.setAmountType(AccountAmountTypeEnum.WITHDRAW_FEE);
                withdrawFeeTotalDTO.setAmount(BigDecimal.ZERO.subtract(withdrawOrder.getRealFee()));
                moneyTotalLocalService.moneyTotal(withdrawFeeTotalDTO);
            } else {
                //以前没有提现成功过，还需要减少提现冻结金额
                MoneyTotalDTO withdrawFreezeMoneyTotalDTO = new MoneyTotalDTO();
                withdrawFreezeMoneyTotalDTO.setUserId(withdrawOrder.getUserId());
                withdrawFreezeMoneyTotalDTO.setAccountId(withdrawOrder.getAccountId());
                withdrawFreezeMoneyTotalDTO.setAmountType(AccountAmountTypeEnum.WITHDRAW_FREEZE);
                withdrawFreezeMoneyTotalDTO.setAmount(BigDecimal.ZERO.subtract(withdrawOrder.getAmount()));
                moneyTotalLocalService.moneyTotal(withdrawFreezeMoneyTotalDTO);
            }

            //如果是融360的标的需要通知
            if (WithdrawBusinessTypeEnum.R360_USER_LOAN.getValue().equals(withdrawOrder.getBusinessType())
                    || WithdrawBusinessTypeEnum.CARD_NIU_USER_LOAN.getValue().equals(withdrawOrder.getBusinessType())
                    || WithdrawBusinessTypeEnum.ORG_USER_LOAN.getValue().equals(withdrawOrder.getBusinessType())){
                projectLendAccountingLocalService.autoWithdrawResultNotify(withdrawOrder.getId(), WithdrawOrderStatusEnum.FAIL.getCode());
            }

            this.returnedPrize(withdrawOrder.getUserId(), withdrawOrder.getPrizeId(),withdrawOrderId);

            //审核不通过的提现不发送短信
            if(!WithdrawOrderAuditStatusEnum.NOT_PASS.getValue().equals(withdrawOrder.getAuditStatus())){
                TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                    @Override
                    public void afterCommit() {
                        super.afterCommit();
                        SendMsgForWithdrawDTO sendMsgForWithdrawDTO = new SendMsgForWithdrawDTO();
                        try {
                            sendMsgForWithdrawDTO.setUserId(withdrawOrder.getUserId());
                            sendMsgForWithdrawDTO.setAmount(withdrawOrder.getAmount());
                            sendMsgForWithdrawDTO.setDateTime(withdrawOrder.getCreateTime());
                            messageSendLocalService.sendMsgForWithdrawFail(sendMsgForWithdrawDTO);
                        } catch (Exception e) {
                            log.error("发送短信/站内信消息-提现失败-异常：{}", JSON.toJSONString(sendMsgForWithdrawDTO), e);
                        }

                    }
                });
            }
        }
    }

    /**
     * 平台提现出款失败
     */
    public void withdrawPaymentPlateFail(WithdrawOrder withdrawOrder, Long updateUserId, WithdrawEndTypeEnum endTypeEnum) {
        //修改提现确认订单状态
        withdrawOrderService.failWithdrawOrder(withdrawOrder.getId(), updateUserId, endTypeEnum);
        //关闭账单
        billFacade.closeAndRevertBill(withdrawOrder.getId().toString(), OrderTypeEnum.WITHDRAW,"");

        if (withdrawOrder.getStatus().equals(WithdrawOrderStatusEnum.SUCCESS.getCode())) {
            //以前是提现成功过，则需要减少累计提现总额
            MoneyTotalDTO withdrawTotalDTO = new MoneyTotalDTO();
            withdrawTotalDTO.setUserId(withdrawOrder.getUserId());
            withdrawTotalDTO.setAccountId(withdrawOrder.getAccountId());
            withdrawTotalDTO.setAmountType(AccountAmountTypeEnum.WITHDRAW_TOTAL);
            withdrawTotalDTO.setAmount(BigDecimal.ZERO.subtract(withdrawOrder.getRealAmout()));
            moneyTotalLocalService.moneyTotal(withdrawTotalDTO);
        }

    }



    /**
     * 关闭提现订单方法
     *
     * @param userId
     * @param withdrawOrderId
     * @param prizeId
     */
    public void closeWithdrawOrder(String userId, Long withdrawOrderId, Long prizeId) {
        log.info("closeWithdrawOrder{}", withdrawOrderId);
        //返还红包
        if (prizeId != null) {
            returnedPrize(userId, prizeId,withdrawOrderId);
        }
        //关闭提现订单
        withdrawOrderService.updateStatus(withdrawOrderId, WithdrawOrderStatusEnum.CLOSE, null);
    }

    //返现提现红包
    private void returnedPrize(String userId, Long prizeId,Long withdrawOrderId) {
        if (prizeId == null) {
            return;
        }
        try{
            UserPrizeResponseDTO userPrizeResponseDTO = activityPrizeDubboService.getUserPrizeInfo(userId,prizeId);
            log.info("返还提现红包查询红包结果：{}",JSON.toJSONString(userPrizeResponseDTO));
            //如果红包不存在当作返还成功,不做返还操作
            if(userPrizeResponseDTO == null){
                log.info("返还提现红包查询红包不存在直接返回，userId:{},withdrawOrderId:{},prizeId:{}",userId,withdrawOrderId,prizeId);
                return;
            }
            //如果红包未使用当作返还成功,不做返还操作
            if(!UserPrizeUseEnum.USED.getType().equals(userPrizeResponseDTO.getIsUsed())){
                log.info("返还提现红包查询红包未使用直接返回，userId:{},withdrawOrderId:{},prizeId:{}",userId,withdrawOrderId,prizeId);
                return;
            }
            //如果返还时此红包已被其它订单使用,当作返还成功,不做返还操作
            if(!String.valueOf(withdrawOrderId).equals(userPrizeResponseDTO.getOrderNo())){
                log.info("返还提现红包查询红包已被其它订单使用直接返回，userId:{},withdrawOrderId:{},prizeId:{}",userId,withdrawOrderId,prizeId);
                return;
            }
        }catch(Exception e){
            log.error("返还提现红包，查询提现红包异常,userId:{},withdrawOrderId:{},prizeId:{}",userId,withdrawOrderId,prizeId,e);
            throw e;
        }

        ActivityPrizeResetStatusReqDTO activityPrizeResetStatusReqDTO = new ActivityPrizeResetStatusReqDTO();
        activityPrizeResetStatusReqDTO.setUserId(userId);
        activityPrizeResetStatusReqDTO.setPrizeId(prizeId);
        //如果红包未占用，当成返还成功。
        try {
            log.info("返还提现红包{}", prizeId);
            boolean result = activityPrizeDubboService.resetPrizeToReturned(activityPrizeResetStatusReqDTO);
            log.info("返还提现红包结果{}:{}", prizeId, result);
        } catch (BizException be) {
            log.error("返还提现红包异常{}", prizeId, be);
            if ("ACTSTAGE10025".equals(be.getErrorCode())) {
                log.info("withdrawPreSubmissionJob红包未占用:{}", prizeId);
            } else {
                throw be;
            }
        } catch(Exception e){
            log.error("返还提现红包系统异常,userId:{},withdrawOrderId:{},prizeId:{}",userId,withdrawOrderId,prizeId,e);
            throw e;
        }
    }

    @Transactional
    public WithdrawConfirmOrder initWithdrawConfirm(Long withdrawOrderId) {
        WithdrawOrder withdrawOrder = withdrawOrderMapperExt.selectByPrimaryKeyForUpdate(withdrawOrderId);
        if (withdrawOrder == null) {
            throw new BizException("ACC10031");
        }
        if (!WithdrawOrderStatusEnum.WAIT_CONFIRM.getCode().equals(withdrawOrder.getStatus())
                || !WithdrawOrderAuditStatusEnum.PASS.getValue().equals(withdrawOrder.getAuditStatus())) {
            log.error("提现确认,订单状态有误:{}", JSON.toJSONString(withdrawOrder));
            throw new BizException("ACC10036");
        }
        WithdrawConfirmOrder withdrawConfirmOrder = new WithdrawConfirmOrder();
        withdrawConfirmOrder.setWithdrawOrderId(withdrawOrderId);
        withdrawConfirmOrderService.addWithdrawConfirmOrder(withdrawConfirmOrder);
        return withdrawConfirmOrder;
    }

    @Transactional
    public WithdrawCancelOrder initWithdrawCancel(Long withdrawOrderId) {
        WithdrawOrder withdrawOrder = withdrawOrderMapperExt.selectByPrimaryKeyForUpdate(withdrawOrderId);
        if (withdrawOrder == null) {
            throw new BizException("ACC10031");
        }
        if (!WithdrawOrderStatusEnum.WAIT_CONFIRM.getCode().equals(withdrawOrder.getStatus())
                || !WithdrawOrderAuditStatusEnum.NOT_PASS.getValue().equals(withdrawOrder.getAuditStatus())) {
            log.error("提现确认,订单状态有误:{}", JSON.toJSONString(withdrawOrder));
            throw new BizException("ACC10036");
        }
        WithdrawCancelOrder withdrawCancelOrder = new WithdrawCancelOrder();
        withdrawCancelOrder.setWithdrawOrderId(withdrawOrderId);
        withdrawCancelOrderService.addWithdrawCancelOrder(withdrawCancelOrder);
        return withdrawCancelOrder;
    }

    @Transactional
    public void updateWithdrawConfirm(Long withdrawOrderId, Long withdrawConfirmOrderId, WithdrawConfirmOrderStatusEnum orderStatusEnum) {
        //修改提现确认订单的状态
        withdrawConfirmOrderService.updateStatus(withdrawConfirmOrderId, orderStatusEnum, 0L);

        //只有确认成功才可以更新提现状态
        if (orderStatusEnum == WithdrawConfirmOrderStatusEnum.SUCCESS) {
            //修改提现订单的状态
            withdrawOrderService.updateStatus(withdrawOrderId, WithdrawOrderStatusEnum.OUTING, 0L);
        }
    }


    /**
     * 提现确认成功方法（自动提现成功与提现确认成功共用此方法）
     */
    @Transactional
    public void withdrawConfirmSuccess(Long withdrawOrderId, Long withdrawConfirmOrderId,BigDecimal advanceAmount,RemitTypeEnum remitType){
        //修改提现确认订单状态为成功
        if(withdrawConfirmOrderId != null){
            withdrawConfirmOrderService.updateStatus(withdrawConfirmOrderId, WithdrawConfirmOrderStatusEnum.SUCCESS, 0L);
        }
        //更新提现订单状态
        WithdrawOrder updateWithdrawOrder = new WithdrawOrder();
        updateWithdrawOrder.setId(withdrawOrderId);
        updateWithdrawOrder.setStatus(WithdrawOrderStatusEnum.OUTING.getCode());//出款中
        updateWithdrawOrder.setAdvanceAmount(advanceAmount == null ? BigDecimal.ZERO:advanceAmount);//垫资金额
        updateWithdrawOrder.setRemitType(remitType==null?null:remitType.getValue());//实际出款类型
        updateWithdrawOrder.setUpdateManager(0L);
        updateWithdrawOrder.setUpdateTime(new Date());
        withdrawOrderMapperExt.updateByPrimaryKeySelective(updateWithdrawOrder);

    }


    @Transactional
    public void updateWithdrawCancel(Long withdrawOrderId,
                                     Long withdrawCancelOrderId,
                                     WithdrawCancelOrderStatusEnum orderStatusEnum,
                                     String requestNo,
                                     WithdrawEndTypeEnum endTypeEnum) {
        WithdrawService withdrawService = (WithdrawService) AopContext.currentProxy();
        //修改提现取消订单的状态
        withdrawCancelOrderService.updateStatus(withdrawCancelOrderId, orderStatusEnum, 0L);
        //只有确认成功才可以更新提现状态
        if (orderStatusEnum == WithdrawCancelOrderStatusEnum.SUCCESS) {
            //提现失败
            withdrawService.withdrawPaymentFail(requestNo, 0L, endTypeEnum);
        }
    }

    //实时查询存管上的账户信息
    public QueryUserInformationResponse queryAccountInfoRealTime(String accountNo) {
        QueryUserInformationRequest queryUserInformationRequest = new QueryUserInformationRequest();
        queryUserInformationRequest.setPlatformUserNo(accountNo);
        CompletableFuture<QueryUserInformationResponse> userInformationResponseCompletableFuture = lanMaoDirectService.queryUserInformation(queryUserInformationRequest);

        QueryUserInformationResponse userInformationResponse = null;
        try {
            userInformationResponse = userInformationResponseCompletableFuture.get();
        } catch (Exception e) {
            log.error("查询存管账户异常:{}",accountNo,e);
            throw new BizException("ACC17011");
        }

        return userInformationResponse;
    }

    private void saveAccountBillList(WithdrawOrder withdrawOrder) {
        //获取不同用户主体提现的二级科目
        AccountBase platformAccount = accountService.loadNiiwooAccount(PlatformConstant.PLATFORM_USER_ID, UserRoleEnum.PLATFORM_INCOME);
        BillSecondSubjectEnum billSecondSubjectEnumUser;
        BillSecondSubjectEnum billSecondSubjectEnumFee;
        if (withdrawOrder.getAccountRole().equals(UserRoleEnum.GUARANTEECORP.getValue()) ) {
            log.info("担保机构提现账单", withdrawOrder.getAccountRole());
            billSecondSubjectEnumUser = BillSecondSubjectEnum.GUARANTEE_AGENCY_WITHDRAW_AMOUNT;
            billSecondSubjectEnumFee = BillSecondSubjectEnum.GUARANTEE_AGENCY_WITHDRAW_FEE;
        }else if (withdrawOrder.getAccountRole().equals(UserRoleEnum.COLLABORATOR.getValue()) ) {
            log.info("合作机构提现账单", withdrawOrder.getAccountRole());
            billSecondSubjectEnumUser = BillSecondSubjectEnum.COOPERATE_AGENCY_WITHDRAW_AMOUNT;
            billSecondSubjectEnumFee = BillSecondSubjectEnum.COOPERATE_AGENCY_WITHDRAW_FEE;
        }else {
            log.info("个人提现账单", withdrawOrder.getAccountRole());
            billSecondSubjectEnumUser = BillSecondSubjectEnum.USER_WITHDRAW;
            billSecondSubjectEnumFee = BillSecondSubjectEnum.USER_WITHDRAW_SERVICE_FEE;
        }

        /**============================用户账单===============================*/
        AddBillAndChangeBalanceDTO userAddBillAndChangeBalanceDTO = new AddBillAndChangeBalanceDTO();
        userAddBillAndChangeBalanceDTO.setAccountId(withdrawOrder.getAccountId());
        userAddBillAndChangeBalanceDTO.setAmount(withdrawOrder.getAmount());
        userAddBillAndChangeBalanceDTO.setInoutType(InoutTypeEnum.OUT_TYPE);
        userAddBillAndChangeBalanceDTO.setOrderId(withdrawOrder.getId());
        userAddBillAndChangeBalanceDTO.setOrderType(OrderTypeEnum.WITHDRAW);
        userAddBillAndChangeBalanceDTO.setRequestNo(withdrawOrder.getRequestNo());
        userAddBillAndChangeBalanceDTO.setStatus(BillStatusEnum.HANDLING);
        userAddBillAndChangeBalanceDTO.setChannelCode(ChannelCodeEnum.APP);
        userAddBillAndChangeBalanceDTO.setRelationUserId(platformAccount.getUserId());
        userAddBillAndChangeBalanceDTO.setRelationAccountId(platformAccount.getId());
        userAddBillAndChangeBalanceDTO.setAddBillDetailDTOList(new ArrayList<>());

        //用户提现金额
        AddBillDetailDTO addBillDetailDTO = new AddBillDetailDTO();
        addBillDetailDTO.setAmount(withdrawOrder.getRealAmout());
        addBillDetailDTO.setBillSecondSubjectEnum(billSecondSubjectEnumUser);
        userAddBillAndChangeBalanceDTO.getAddBillDetailDTOList().add(addBillDetailDTO);

        //用户提现手续费
        addBillDetailDTO = new AddBillDetailDTO();
        addBillDetailDTO.setAmount(withdrawOrder.getRealFee());
        addBillDetailDTO.setBillSecondSubjectEnum(billSecondSubjectEnumFee);
        userAddBillAndChangeBalanceDTO.getAddBillDetailDTOList().add(addBillDetailDTO);


        /**============================平台账单=================================*/
        AddBillAndChangeBalanceDTO platformAddBillAndChangeBalanceDTO = new AddBillAndChangeBalanceDTO();
        platformAddBillAndChangeBalanceDTO.setAccountId(platformAccount.getId());
        platformAddBillAndChangeBalanceDTO.setAmount(withdrawOrder.getRealFee());
        platformAddBillAndChangeBalanceDTO.setInoutType(InoutTypeEnum.IN_TYPE);
        platformAddBillAndChangeBalanceDTO.setOrderId(withdrawOrder.getId());
        platformAddBillAndChangeBalanceDTO.setOrderType(OrderTypeEnum.WITHDRAW);
        platformAddBillAndChangeBalanceDTO.setRequestNo(withdrawOrder.getRequestNo());
        platformAddBillAndChangeBalanceDTO.setStatus(BillStatusEnum.HANDLING);
        platformAddBillAndChangeBalanceDTO.setChannelCode(ChannelCodeEnum.APP);
        platformAddBillAndChangeBalanceDTO.setRelationUserId(withdrawOrder.getUserId());
        platformAddBillAndChangeBalanceDTO.setRelationAccountId(withdrawOrder.getAccountId());
        platformAddBillAndChangeBalanceDTO.setAddBillDetailDTOList(new ArrayList<>());

        //平台提现手续费
        addBillDetailDTO = new AddBillDetailDTO();
        addBillDetailDTO.setAmount(withdrawOrder.getRealFee());
        addBillDetailDTO.setBillSecondSubjectEnum(BillSecondSubjectEnum.PLATFORM_SERVICE_FEE_IN_WITHDRAW);
        platformAddBillAndChangeBalanceDTO.getAddBillDetailDTOList().add(addBillDetailDTO);


        //保存账单及账单流水
        List<AddBillAndChangeBalanceDTO> addBillAndChangeBalanceDTOList = new ArrayList<>();
        addBillAndChangeBalanceDTOList.add(userAddBillAndChangeBalanceDTO);
        addBillAndChangeBalanceDTOList.add(platformAddBillAndChangeBalanceDTO);
        billFacade.batchAddBillAndChangeBalance(addBillAndChangeBalanceDTOList);
    }

    /**
     * 资金回退充值记录
     * @param rollbackRechargeOrder
     */
    public void addBackrollRechargeOrder(RollbackRechargeOrder rollbackRechargeOrder){
        rollbackRechargeOrderMapper.insertSelective(rollbackRechargeOrder);
    }

    /**
     * 平台申请提现回调处理
     *
     * @param notifyRequest
     * @return
     */
    @Transactional
    public Long processSubmitWithdrawPlateNotify(WithdrawNotifyRequestDTO notifyRequest) {
        //查询并锁定提现订单
        String requestNo = notifyRequest.getRequestNo();
        WithdrawOrder withdrawOrder = withdrawOrderService.loadWithdrawOrderByRequestNo(requestNo);
        withdrawOrder = withdrawOrderMapperExt.selectByPrimaryKeyForUpdate(withdrawOrder.getId());
        if (withdrawOrder.getStatus().equals(WithdrawOrderStatusEnum.PRE_SUBMISSION.getCode())) {
            //修改提现订单的状态
            WithdrawOrder withdrawOrderRecord = new WithdrawOrder();
            withdrawOrderRecord.setId(withdrawOrder.getId());
            withdrawOrderRecord.setAuditStatus(WithdrawOrderAuditStatusEnum.PASS.getValue());
            withdrawOrderRecord.setStatus(WithdrawOrderStatusEnum.OUTING.getCode());
            withdrawOrderRecord.setAdvanceAmount(notifyRequest.getFloatAmount());
            withdrawOrderMapper.updateByPrimaryKeySelective(withdrawOrderRecord);

            //变更余额 + 记账
            AddBillDetailDTO addBillDetailDTO = new AddBillDetailDTO();
            addBillDetailDTO.setAmount(withdrawOrder.getRealAmout());
            addBillDetailDTO.setBillSecondSubjectEnum(BillSecondSubjectEnum.PLATFORM_WITHDRAW_AMOUNT);

            AddBillAndChangeBalanceDTO billDTO = new AddBillAndChangeBalanceDTO();
            billDTO.setAccountId(withdrawOrder.getAccountId());
            billDTO.setAmount(withdrawOrder.getAmount());
            billDTO.setInoutType(InoutTypeEnum.OUT_TYPE);
            billDTO.setOrderId(withdrawOrder.getId());
            billDTO.setOrderType(OrderTypeEnum.WITHDRAW);
            billDTO.setRequestNo(withdrawOrder.getRequestNo());
            billDTO.setStatus(BillStatusEnum.HANDLING);
            billDTO.setChannelCode(ChannelCodeEnum.APP);
            billDTO.setRelationUserId(withdrawOrder.getUserId());
            billDTO.setRelationAccountId(withdrawOrder.getAccountId());
            billDTO.setAddBillDetailDTOList(Arrays.asList(addBillDetailDTO));
            billFacade.addBillAndChangeBalance(billDTO);
        }

        return withdrawOrder.getId();
    }


    /**
     * 放款提现,必须在放款入账事务内运行，先加帐再减帐，所以此方法并不会判断余额(目前只有融360用到)
     *
     * @return
     */
    @Transactional(propagation = Propagation.MANDATORY)
    public WithdrawOrder submitLoanWithdraw(SubmitLoanWithdrawRequestDTO request) {
        log.info("账户中心自动提现接口入参:{}",JSON.toJSONString(request));
        //根据账户ID精确查询账户
        AccountBase accountBase = accountService.loadAccountById(request.getAccountId());
        //账户未激活
        if (AccountActiveEnum.UNACTIVATED.getValue().equals(accountBase.getImportUserActiva())) {
            throw new BizException("ACC10003");
        }

        //查询用户银行卡信息
        BankCard bankCard = bankCardService.loadBankCard(accountBase);


//        withdrawFee = request.getAmount().multiply(request.getWithdrawFeeRate()).setScale(2, BigDecimal.ROUND_HALF_DOWN);
//        if (request.getMaxWithdrawFee().compareTo(BigDecimal.ZERO) != 0) {
//            if (withdrawFee.compareTo(request.getMaxWithdrawFee()) > 0) {
//                withdrawFee = request.getMaxWithdrawFee();
//            }
//        }
        WithdrawFeeDTO feeDTO = caculateFee(request.getFeePaymentUserType(),request.getAmount(),request.getWithdrawFeeRate(),request.getMaxWithdrawFee());
        BigDecimal withdrawRealFee = feeDTO.getWithdrawRealFee();
        BigDecimal fee = feeDTO.getFee();
        //实际提现金额 = 放款金额 - 手续费
        BigDecimal realAmount = request.getAmount().subtract(withdrawRealFee);
        WithdrawOrder withdrawOrder = new WithdrawOrder();

        //垫资金额
        BigDecimal advanceAmount = request.getAmount().subtract(withdrawRealFee);
        advanceAmount = advanceAmount.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO :advanceAmount;

        //初始化提现订单
        withdrawOrder.setId(snowflakeIdWorker.nextId());
        withdrawOrder.setRequestNo(lanMaoSequence.getRequestNo());
        withdrawOrder.setUserId(accountBase.getUserId());
        withdrawOrder.setAccountId(accountBase.getId());
        withdrawOrder.setAccountRole(accountBase.getAccountRole());
        withdrawOrder.setRealName(bankCard.getRealName());
        withdrawOrder.setMobileNo(privacyMasks.encryptPrivacy(request.getMobileNo()));
        withdrawOrder.setBankCardId(bankCard.getId());
        withdrawOrder.setBankCode(bankCard.getBankCode());
        withdrawOrder.setBusinessType(request.getBusinessType().getValue());
        withdrawOrder.setWithdrawType(WithdrawTypeEnum.URGENT.getValue());//全部走加急T0
        withdrawOrder.setAdvanceAmount(advanceAmount);//默认全额垫资(手续费无需垫资)
        withdrawOrder.setIsAuto(WithdrawAutoType.AUTO.getValue());//自动提现
        withdrawOrder.setAmount(request.getAmount());
        withdrawOrder.setRealAmout(realAmount);
        withdrawOrder.setFee(fee); //应付提现手续费
        withdrawOrder.setRealFee(withdrawRealFee);
        withdrawOrder.setWithdrawFeeRate(request.getWithdrawFeeRate()); //费率
        withdrawOrder.setFeePaymentUserType(request.getFeePaymentUserType()); //提现服务费收取类型:1：借款人、2：机构、3：你我金融；只对1,3做处理
        withdrawOrder.setStatus(WithdrawOrderStatusEnum.WAIT_CONFIRM.getCode());
        withdrawOrder.setCreateTime(new Date());
        withdrawOrderService.initWithdrawOrder(withdrawOrder);

		log.info("###新增待审核的放款提现单###, 提现单requestNo={}, 账户ID={}, 提现金额={}, 到账金额={}, 提现服务费费率={}, 应付提现服务费={}, 借款人应付提现服务费={}.",
				withdrawOrder.getRequestNo(), request.getAccountId(), request.getAmount(), realAmount,
				request.getWithdrawFeeRate(), fee, withdrawRealFee);
        
        //新增提现审核记录
        WithdrawOrderAudit withdrawOrderAudit = new WithdrawOrderAudit();
        withdrawOrderAudit.setWithdrawOrderId(withdrawOrder.getId());
        withdrawOrderAudit.setApplyTime(withdrawOrder.getCreateTime());
        withdrawOrderAuditService.addWithdrawOrderAudit(withdrawOrderAudit);
        //新增用户账单和平台账单
        this.saveAccountBillList(withdrawOrder);
        //增加提现冻结总额
        MoneyTotalDTO moneyTotalDTO = new MoneyTotalDTO();
        moneyTotalDTO.setUserId(withdrawOrder.getUserId());
        moneyTotalDTO.setAccountId(withdrawOrder.getAccountId());
        moneyTotalDTO.setAmountType(AccountAmountTypeEnum.WITHDRAW_FREEZE);
        moneyTotalDTO.setAmount(withdrawOrder.getAmount());
        moneyTotalLocalService.moneyTotal(moneyTotalDTO);
        //增加应垫资总额
        withdrawOrderService.increAdvanceAmountTotal(advanceAmount);
        return withdrawOrder;

    }

    /**
     * 计算提现手续费
     * @param userType 提现服务费收取类型:1：提现人、2：机构、3：你我金融
     * @param amount 提现金额
     * @param feeRate 提现费率
     * @param maxWithdrawFee 最大提现手续费
     * @return
     */
    public WithdrawFeeDTO caculateFee(Byte userType, BigDecimal amount, BigDecimal feeRate, BigDecimal maxWithdrawFee) {
        log.info("计算提现手续费,接收参数信息:{'userType':"+userType+",'amount':"+amount+",'feeRate':"+feeRate+",'maxWithdrawFee':"+maxWithdrawFee+"}");
        Assert.notNull(userType,"提现服务费收取类型不能为空");
        Assert.notNull(amount,"提现金额不能为空");
        Assert.notNull(feeRate,"提现费率不能为空");
        Assert.notNull(maxWithdrawFee,"最大提现手续费不能为空");
        //获取配置：手续费率&最大提现手续费
        //计算手续费
        BigDecimal withdrawRealFee = null; //提现实际提现手续费
        BigDecimal fee = null; //应付提现手续费
        switch (userType) { //提现服务费收取类型:1：提现人、2：机构、3：你我金融
            case 3: //你我金融
                fee = caculateFee(amount,feeRate,maxWithdrawFee);
                withdrawRealFee = BigDecimal.ZERO;
                break;
            case 2: //机构，已废弃，机构应垫付的提现费用由平台垫付，然后平台与机构线下结算
                throw new BizException("ACC10028"); //未配置提现手续费率
            case 1: //提现人
            default: //提现人
                fee = caculateFee(amount,feeRate,maxWithdrawFee);
                withdrawRealFee = fee; // 如果是提现人支付提现服务费，则平台垫付资金为零
                break;
        }

        return new WithdrawFeeDTO(fee,withdrawRealFee);
    }

    private BigDecimal caculateFee(BigDecimal amount,BigDecimal feeRate,BigDecimal maxWithdrawFee) {
        BigDecimal fee = amount.multiply(feeRate).setScale(2, BigDecimal.ROUND_HALF_EVEN); //默认快速提现
        // 如果计算提现手续费大于单次提现最高收取，取单次提现最高收取
        if (maxWithdrawFee.compareTo(BigDecimal.ZERO) != 0) {
            if (fee.compareTo(maxWithdrawFee) > 0) {
                fee = maxWithdrawFee;
            }
        }

        return fee;
    }


}
